package com.meevle.business;

import java.io.File;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.red5.core.ApplicationSettings;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;

import com.meevle.dao.SlotCommentDAO;
import com.meevle.dao.SetDAO;
import com.meevle.dao.SlotDAO;
import com.meevle.dao.UserDAO;
import com.meevle.utilities.Counter;
import com.meevle.utilities.DaoToVoAdapter;
import com.meevle.utilities.HibernateManager;
import com.meevle.utilities.MD5HashCalculator;
import com.meevle.utilities.RegexController;
import com.meevle.utilities.VoToDAoAdapter;
import com.meevle.vo.SetVO;
import com.meevle.vo.SlotCommentVO;
import com.meevle.vo.SlotVO;
import com.meevle.vo.UserVO;

public class UserDelegate {

	private static Logger log = Red5LoggerFactory.getLogger(UserDelegate.class,
			"Meevle");

	/**
	 * Returns all the projects of a user of which he's the owner
	 * 
	 * @param user
	 *            the user of whom you'd like to have all the projects of
	 * @return a list of Projects
	 * @throws IllegalArgumentException
	 *             if something was wrong with the parameter. The
	 *             Exceptionmessage should tell you more about the reason.
	 * @throws Exception If something was wrong with the DB access
	 */
	public List<SetVO> getSets(UserVO user)throws IllegalArgumentException, Exception
	{
		List<SetVO> projects = new ArrayList<SetVO>();
		List<SetDAO> projectDaos;
		try {
//			projectDaos = UserDAO.getProjectsByUser(user);
			UserDAO u = UserDAO.getUser(user);
			projectDaos = u.getSets();
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (Exception e)
		{
			throw e;
		}

		try {
			for (SetDAO projectDao : projectDaos)
				projects.add(DaoToVoAdapter.getInstance()
						.getSetFromSetDAO(projectDao));
		} catch (NullPointerException e) {
			log.error(e.getMessage());
		}

		return projects;
	}

	/**
	 * Returns all the Tracks of the user
	 * 
	 * @param restrictedUser
	 *            the user of whom you want all the tracks
	 * @return
	 * @throws IllegalArgumentException
	 *             if something was wrong with the parameter. The
	 *             Exceptionmessage should tell you more about the reason.
	 */
	public List<SlotVO> getSlots(UserVO user) throws IllegalArgumentException, Exception
	{
		List<SlotVO> tracks = new ArrayList<SlotVO>();
		List<SlotDAO> trackDaos;
		try {
//			trackDaos = UserDAO.getTracksByUser(user);
			UserDAO u = UserDAO.getUser(user);
			trackDaos = u.getSlots();
		} catch (IllegalArgumentException e) {
			throw e;
		} catch(Exception e) {
			throw e;
		}

		try {
			for (SlotDAO trackDao : trackDaos)
				tracks.add(DaoToVoAdapter.getInstance().getSlotFromSlotDAO(
						trackDao));
		} catch (NullPointerException e) {
			log.error(e.getMessage());
		}
		return tracks;
	}

	/**
	 * log a user in
	 * 
	 * @param user
	 * @return true if login succeeded
	 * @throws IllegalArgumentException if something as wrong with the parameters
	 */

	public static boolean login(String username, String password) throws IllegalArgumentException
	{
		boolean ret = false;
//		if (Counter.getInstance().counter == 0) {
//			initializeDB();
//			Counter.getInstance().higher();
//		}

		try {
			RegexController.getInstance().checkUsername(username);
			RegexController.getInstance().checkPassword(password);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw e;
		}
		
		ret = validateUser(username, password);
		return ret;

	}

	/**
	 * Log a user out
	 * 
	 * @param user
	 * @return true if logout succeeded, false if not
	 * @throws IllegalArgumentException if something was wrong with the user
	 */
	public boolean logout(UserVO user)throws IllegalArgumentException
	{
		boolean ret = true;
			try {
				RegexController.getInstance().checkUsername(user.getUsername());
			} catch (IllegalArgumentException e) {
				throw e;
			}
		return ret;
	}

	/**
	 * Creates a new user if all went well
	 * 
	 * @param user
	 *            the user you'd like to create
	 * @return True if all went well, false if creation failed
	 * @throws IllegalArgumentException
	 *             if something's wrong with the parameters. The message should
	 *             say enough.
	 * @throws Exception
	 *             when something went wrong with the insertion of the user in
	 *             the DB
	 */
	public static boolean createUser(UserVO user, String password)throws IllegalArgumentException, Exception {
		
		boolean creationSuccess = false;
		boolean userExists = true;
		
		if (user != null && user.getUsername().trim() != "" && password.trim() != "" && user.getUsername().trim().matches("^[a-zA-Z0-9-][a-zA-Z0-9_-]{3,19}") )
		{
			
			try {
				RegexController.getInstance().checkUsername(user.getUsername());
			} catch (IllegalArgumentException e) {
				throw e;
			}
			
			try {
				// does such a user exist already?
				UserDAO.getUser(user);
			} catch (IllegalArgumentException ill) {
				userExists = false;
			}
			
			if(!userExists)
			{
				boolean b = createUserDirectories(user);
				
				// insert the user in the DB AFTER the maps have been created, if
				// not, this could give problems
				if(b)
				{
					try {
						persistUser(user, password);
					} catch (Exception e) {
						throw new Exception("Sorry, for the inconvenience but you'll have to try again a bit later");
						// throw e;
					}
				}
				else {
					log.error("Something went wrong during the making of the directory structure");
					throw new Exception("Sorry, but you'll have to try again a bit later");
				}
				creationSuccess = true;
			}
		} //end big if
		
		return creationSuccess;
	}

	/**
	 * Creates the temp and the tracks directories of the new user
	 * @param user
	 * @return True if the creation of the directories was successfull, false if not
	 */
	private static boolean createUserDirectories(UserVO user)
	{
		boolean ret = new File(ApplicationSettings.getInstance()
				.getContextFullPath()
				+ ApplicationSettings.getInstance().getUserTempPath(user.getUsername()))
				.mkdirs();
		
		ret = new File(ApplicationSettings.getInstance()
				.getContextFullPath()
				+ ApplicationSettings.getInstance().getUserTracksPath(user.getUsername()))
				.mkdirs();
		
		return ret;
	}

	/**
	 * Validate a user, in other words, does the username exist in the DB,
	 * accompanied with the provided password
	 * 
	 * @param username
	 *            The entered username
	 * @param password
	 *            The entered password
	 * @return true if validation is ok, false if not. Probably because the user
	 *         entered a wrong password
	 * @throws IllegalArgumentException
	 *             when a user with that username does not exist (Not Anymore)
	 */

	private static boolean validateUser(String username, String password)
			throws IllegalArgumentException {

		UserDAO u = null;
		boolean ret = true;
		try {
			u = UserDAO.getUser(new UserVO(username));
			if (!u.getPassword().equals(password))
				ret = false;
		} catch (IllegalArgumentException e) {
			ret = false;
			log.error(e.getMessage());
			// throw e;
		} catch (Exception e)
		{
			ret = false;
			log.error(e.getMessage());
		}
		return ret;
	}

	/**
	 * Get all the users from the database
	 * 
	 * @return a list of <code>RestrictedUserVO</code>objects
	 */
	public static List<UserVO> getAllUsers()
	{
		List<UserVO> ret = new ArrayList<UserVO>();
		List<UserDAO> userDaos = new ArrayList<UserDAO>();
		try {
			userDaos = UserDAO.getAll();
		} catch (Exception e) {
			;
		}

		for (UserDAO userDao : userDaos)
			ret.add(DaoToVoAdapter.getInstance().getUserFromUserDAO(userDao));
		return ret;
	}

	/**
	 * Get a <code>UserVO</code> Object from the database with all the
	 * properties set
	 * 
	 * @param userVo
	 *            a <code>UserVO</code> object which probably hasn't got all the
	 *            properties yet
	 * @return a <code>UserVO</code> object with all properties set or null if
	 *         for example userVo was null
	 * @throws IllegalArgumentException
	 *             if something was wrong with the parameter (e.g. it doesn't
	 *             exist in the database)
	 * @throwe Exception If something went wrong during the DB access
	 */
	public static UserVO getUser(UserVO userVo) throws IllegalArgumentException, Exception
	{
		UserVO user = null;
		try {
			RegexController.getInstance().checkUsername(userVo.getUsername());
			user = DaoToVoAdapter.getInstance().getUserFromUserDAO(
					UserDAO.getUser(userVo));
		} catch (NullPointerException e) {
			;
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (Exception e)
		{
			throw e;
		}

		return user;
	}

	/**
	 * Inserts a user into the database
	 * 
	 * @param user
	 *            A com.meevle.vo.UserVO object
	 * @param password
	 *            The password of the new user
	 * @throws Exception
	 *             If something went wrong during the inserting
	 */
	private static void persistUser(UserVO user, String password)
			throws Exception {
		UserDAO u = new UserDAO();
		u.setPassword(password);
		u.setUsername(user.getUsername());
		try {
			UserDAO.persist(u);
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * Is the user owner of this track or not
	 * 
	 * @param trackVo
	 *            The track
	 * @param userVo
	 *            The user
	 * @return True is that user is the owner, false if not.
	 * @throws HibernateException
	 *             if something went wrong while accessing the DB
	 * @throws Exception
	 *             when something else went wrong
	 */
	public static boolean isUserOwnerOfSlot(UserVO userVo, SlotVO trackVo)throws HibernateException, Exception
	{
		boolean ret = false;
		SlotDAO trackDao = null;
		try
		{
			RegexController.getInstance().checkUsername(userVo.getUsername());
			RegexController.getInstance().checkUsername(trackVo.getOwner().getUsername());
			RegexController.getInstance().checkSlotname(trackVo.getName());
				try {
					//does it exist already; throws an exception if not
					trackDao = SlotDAO.getSlot(trackVo);
					ret = trackDao.getOwner().equals(UserDAO.getUser(userVo) );
				} catch (Exception e) {
					e.printStackTrace();
					//ret remains false;
				}
		} catch (HibernateException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}
		return ret;
	}

	/**
	 * Is the user owner of this track or not
	 * 
	 * @param trackVo
	 *            The track
	 * @param userVo
	 *            The user
	 * @return True is that user is the owner, false if not.
	 * @throws HibernateException
	 *             if something went wrong while accessing the DB
	 * @throws Exception
	 *             when something else went wrong
	 */
	public static boolean isUserOwnerOfSet(UserVO userVo,
			SetVO projectVo) throws HibernateException, Exception {
		boolean ret = false;

		try {
			RegexController.getInstance().checkUsername(userVo.getUsername());
			RegexController.getInstance().checkUsername(projectVo.getOwner().getUsername());
			RegexController.getInstance().checkSetname(projectVo.getName());
			ret = UserDAO.getSetsByUser(userVo).contains(SetDAO.getSet(projectVo) );
		} catch (HibernateException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}

		return ret;
	}

	/**
	 * Is a user a participant in a project. An owner is a participant too!! If
	 * you want to check if a user is an owner, then you should use the
	 * <code>isUserOwnerOfProject</code> method
	 * 
	 * @param user
	 * @param project
	 * @return True if the user is a participant (incl. owner), false if not
	 * @throws IllegalArgumentException
	 *             When there's something wrong with the projectparameter
	 * @throws Exception If something went wrong during the DB access
	 */
	public static boolean isUserParticipantInSet(UserVO user, SetVO project) throws IllegalArgumentException, Exception
	{
		boolean ret = false;

		List<SlotDAO> trackDaos;
		try {
			RegexController.getInstance().checkUsername(user.getUsername());
			RegexController.getInstance().checkUsername(project.getOwner().getUsername());
			RegexController.getInstance().checkSetname(project.getName());
			trackDaos = SetDAO.getSet(project).getSlots();
		} catch (IllegalArgumentException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		}

		// check if the owner of the track is equal to the user
		for (SlotDAO trackDao : trackDaos) {
			if (DaoToVoAdapter.getInstance().getSlotFromSlotDAO(trackDao)
					.getOwner().equals(user)) {
				ret = true;
				break;
			}
		}
		return ret;
	}

	/**
	 * Get the comments related to this user
	 * @param userVo The User
	 * @return
	 * @throws IllegalArgumentException If there's something wrong with userVo.Username
	 * @throws Exception
	 */
	public List<SlotCommentVO> getSlotComments(UserVO userVo)throws IllegalArgumentException, Exception
	{
		List<SlotCommentVO> comments = new ArrayList<SlotCommentVO>(0);
		
		try {
			RegexController.getInstance().checkSlotname(userVo.getUsername());
			
			List<SlotCommentDAO> commentsDao = UserDAO.getUser(userVo).getComments();
			
			for(SlotCommentDAO commentDao : commentsDao)
				comments.add(DaoToVoAdapter.getInstance().getSlotCommentVOFromSlotCommentDAO(commentDao));

		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw e;
		} catch (NullPointerException e) {
			e.printStackTrace();
			throw new IllegalArgumentException("The track cannot be null");
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
		
		return comments;
	}
	
	/**
	 * Update a user with new values
	 * @param oldUser
	 * @param newUser
	 * @throws IllegalArgumentException If there was something wrong with the provided parameters
	 * @throws Exception If there went something wrong during the DB access
	 */
	public static void update(UserVO oldUser, UserVO newUser)throws IllegalArgumentException, Exception
	{
		try {
			RegexController.getInstance().checkUsername(oldUser.getUsername());
			RegexController.getInstance().checkUsername(newUser.getUsername());
			
			UserDAO.update(oldUser, newUser);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	private static void initializeDB() {

		UserDAO u = new UserDAO("meevle", MD5HashCalculator.getInstance()
				.getHash("breezerslet84"));
		
		

		
		UserVO userVo = DaoToVoAdapter.getInstance().getUserFromUserDAO(u);
		SlotVO track1Vo = new SlotVO(userVo, new Timestamp(System.currentTimeMillis()), "Heejoh", 1);
		
//		 inserting a new project into the DB
		SetVO project1Vo = new SetVO();
		project1Vo.setName("Troelalaaa");
		project1Vo.setOwner(userVo);
				
//		//ADDING to the DB
//		try {
////			createUser(userVo, u.getPassword());
//			
//			GenreDelegate.createGenre(DaoToVoAdapter.getInstance().getGenreFromGenreDAO(jazz));
//			InstrumentDelegate.createInstrument(DaoToVoAdapter.getInstance().getInstrumentFromInstrumentDAO(basgitaar));
//			
//			UserDAO.persist(u);
//			InstrumentDAO.persist(akoestischeGitaar);
//			InstrumentDAO.persist(stem);
//			GenreDAO.persist(trash);
//			GenreDAO.persist(rockNRoll);
//			GenreDAO.persist(emo);
//			
//			TrackDelegate.createTrack(userVo, track1Vo);
//			ProjectDelegate.createProject(userVo, project1Vo);
//			
//			System.out.println("\nAdden van een track aan een project: " + ProjectDelegate.addTrack(userVo, project1Vo, track1Vo) );
//			System.out.println("\nAlle tracks van het project: " + ProjectDelegate.getAllTracks(project1Vo));
////			UserDelegate.update(userVo, new UserVO("jeroen"));
////			System.out.println("\n owner of track1Vo: " + TrackDelegate.getTrack(track1Vo).getOwner().getUsername() );
//			
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		
//		System.out.println("RMW: alles is toegevoegd");

		SlotDAO track1 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()),
				"Super Duper BassTrack", 2);
		track1.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track1.setFilename("123478.mp3");
		
		SlotCommentDAO commentTrack11 = new SlotCommentDAO();
		commentTrack11.setAuthor(u);
		commentTrack11.setComment("Very nice, amai");
		commentTrack11.setRating(5);
		commentTrack11.setTimestamp(new Date(System.currentTimeMillis()));
		commentTrack11.setSlot(track1);
		
		track1.getComments().add(commentTrack11);
		u.getSlots().add(track1);

		SlotDAO track2 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()),
				"Acoustic Track", 3);
		track2
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track2.setFilename("123478.mp3");

		SlotCommentDAO commentTrack21 = new SlotCommentDAO();
		commentTrack21.setAuthor(u);
		commentTrack21.setComment("Kon beter");
		commentTrack21.setRating(3);
		commentTrack21.setTimestamp(new Date(System.currentTimeMillis()));
		commentTrack21.setSlot(track2);
		
		SlotCommentDAO commentTrack22 = new SlotCommentDAO();
		commentTrack22.setAuthor(u);
		commentTrack22.setComment("Sucks big time. Gimme back my money");
		commentTrack22.setRating(1);
		commentTrack22.setTimestamp(new Date(System.currentTimeMillis()));
		commentTrack22.setSlot(track2);
		
		track2.getComments().add(commentTrack21);
		track2.getComments().add(commentTrack22);
		u.getSlots().add(track2);

		SlotDAO track3 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()), "Acoustic 3", 4);
		track3
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track3.setFilename("123478.mp3");

		u.getSlots().add(track3);

		SlotDAO track4 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()), "Acoustic 4", 5);
		track4
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track4.setFilename("123478.mp3");

		u.getSlots().add(track4);

		SlotDAO track5 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()), "Acoustic 5", 6);
		track5
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track5.setFilename("123478.mp3");

		u.getSlots().add(track5);

		SlotDAO track6 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()), "Acoustic 6", 7);
		track6
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track6.setFilename("123478.mp3");

		u.getSlots().add(track6);

		SlotDAO track7 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()), "Acoustic 7", 8);
		track7
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track7.setFilename("123478.mp3");

		u.getSlots().add(track7);

		SlotDAO track8 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()), "Acoustic 8",1);
		track8
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838862");
		track8.setFilename("123478.mp3");

		u.getSlots().add(track8);

		SlotDAO track9 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()), "Acoustic 9",2);
		track9
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838952");
		track9.setFilename("123478.mp3");

		u.getSlots().add(track9);

		SlotDAO track10 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()),
				"Acoustic 10", 3);
		track10
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838952");
		track10.setFilename("123478.mp3");

		u.getSlots().add(track10);

		SlotDAO track11 = new SlotDAO(u, new Timestamp(System.currentTimeMillis()),
				"Acoustic 11", 4);
		track11
				.setDirectory("/streams/f4b09fa91f3f495fbaeeb6cb70a4e414/5504528cfe395c1daf56b95d48838952");
		track11.setFilename("123478.mp3");

		u.getSlots().add(track11);

		// inserting a new project into the DB
		SetDAO project1 = new SetDAO("Doobidoebieproject", u);
		SetDAO project2 = new SetDAO("Dadada", u);

		u.getSets().add(project1);
		u.getSets().add(project2);
		
		project1.getSlots().add(track1);
		project1.getSlots().add(track2);
		project1.getSlots().add(track3);
		project1.getSlots().add(track4);
		project1.getSlots().add(track5);
		project1.getSlots().add(track6);
		project1.getSlots().add(track7);
		
		project2.getSlots().add(track8);
		project2.getSlots().add(track9);
		project2.getSlots().add(track10);
		project2.getSlots().add(track11);
		
		Session session = HibernateManager.getInstance().getSession();
		session.beginTransaction();

		session.saveOrUpdate(u);

		session.saveOrUpdate(track1);
		session.saveOrUpdate(track2);
		session.saveOrUpdate(track3);
		session.saveOrUpdate(track4);
		session.saveOrUpdate(track5);
		session.saveOrUpdate(track6);
		session.saveOrUpdate(track7);
		session.saveOrUpdate(track8);
		session.saveOrUpdate(track9);
		session.saveOrUpdate(track10);
		session.saveOrUpdate(track11);

		session.saveOrUpdate(project1);
		session.saveOrUpdate(project2);

		session.saveOrUpdate(commentTrack11);
		session.saveOrUpdate(commentTrack21);
		session.saveOrUpdate(commentTrack22);
		
		session.getTransaction().commit();

		log.info("Filled DB");
		}
	}
	
	//TODO deleteUser
	//TODO deleteGenre
	//TODO deleteInstrument
	//TODO deleteTrack
	//TODO deleteProject

